package com.seal.commons.infrastructure.oss;

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ListObjectsV2Result;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectResult;
import com.amazonaws.services.s3.model.S3Object;
import com.seal.commons.exception.StoreException;
import com.seal.commons.infrastructure.facade.store.StoreService;
import com.seal.commons.utils.id.UniqueIdUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;

/**
 * func oss存储相关操作类
 * Date 2022/12/24 17:45<br/>
 *
 * @author yong.huang
 * @since JDK 1.8
 */
@Slf4j
public class OssStoreServiceImpl implements StoreService {

    private AmazonS3 amazonS3;

    private String bucketName;

    public OssStoreServiceImpl(AmazonS3 amazonS3, String bucketName){
        this.amazonS3 = amazonS3;
        this.bucketName = bucketName;
    }

    @Override
    public String upload(File file) throws StoreException  {
        return upload(this.bucketName, file);
    }

    @Override
    public String upload(String bucketName, File file) throws StoreException{
        String ext =  FilenameUtils.getExtension(file.getName());
        String fileId = UniqueIdUtils.uuid() + ext;
        upload(bucketName, fileId, file);
        return fileId;
    }

    @Override
    public String upload(String filePath) throws StoreException {
        return upload(this.bucketName, filePath);
    }

    @Override
    public String upload(String bucketName, String filePath)  throws StoreException{
        File file = new File(filePath);
        String ext =  FilenameUtils.getExtension(file.getName());
        String fileId = UniqueIdUtils.uuid() + ext;
        upload(bucketName, fileId, file);
        return fileId;
    }

    private void upload(String bucketName, String fileId, File file) throws StoreException{
        try{
            log.info("oss 文件上传，bucketName:{} fileId:{}, file:{}", bucketName, fileId, file.getName());
            PutObjectResult putObjectResult = amazonS3.putObject(bucketName, fileId, file);
            log.info("oss 文件上传，bucketName:{} fileId:{}, result:{}", bucketName, fileId, putObjectResult);
        }catch (Exception e){
            log.error("oss 文件上传，bucketName:{} fileId:{}", bucketName, fileId, e);
            throw new StoreException(String.format("oss 文件上传失败，bucketName:%s, fileId:%s", bucketName, fileId), e);
        }
    }

    @Override
    public String upload(MultipartFile multipartFile) throws StoreException{
        return upload(bucketName, multipartFile);
    }

    @Override
    public String upload(String bucketName, MultipartFile multipartFile) throws StoreException{
        try{
            String ext =  FilenameUtils.getExtension(multipartFile.getOriginalFilename());
            String fileId = UniqueIdUtils.uuid() + ext;
            ObjectMetadata objectMetadata = new ObjectMetadata();
            log.info("oss 文件上传，bucketName:{} fileId:{}, file:{}", bucketName, fileId, multipartFile.getOriginalFilename());
            PutObjectResult putObjectResult = amazonS3.putObject(bucketName, fileId, multipartFile.getInputStream(), objectMetadata);
            log.info("oss 文件上传，bucketName:{} fileId:{}, result:{}", bucketName, fileId, putObjectResult);
            return fileId;
        }catch (Exception e){
            log.error("oss 文件上传，bucketName:{} fileName:{}", bucketName, multipartFile.getOriginalFilename() , e);
            throw new StoreException(String.format("oss 文件上传失败，bucketName:%s, fileName:%s", bucketName, multipartFile.getOriginalFilename()), e);
        }
    }

    @Override
    public boolean isExist(String resourcePath) throws StoreException{
        return isExist(this.bucketName, resourcePath);
    }


    @Override
    public boolean isExist(String bucketName, String resourcePath) throws StoreException {
        try {
            ListObjectsV2Result result = amazonS3.listObjectsV2(bucketName, resourcePath);
            return result.getKeyCount() > 0;
        }catch (Exception e){
            throw new StoreException(String.format("判断文件是否存在异常, bucketName:%s, fileId:%s", bucketName, resourcePath),e);
        }
    }

    @Override
    public void read(String resourcePath, File targetFile) throws StoreException  {
        read(bucketName, resourcePath, targetFile);
    }

    @Override
    public void read(String bucketName, String resourcePath, File targetFile) throws StoreException {
        if(targetFile == null || !targetFile.exists()){
            throw new IllegalArgumentException("oss read target file is null or not exists");
        }
        try(S3Object object = amazonS3.getObject(bucketName, resourcePath);
            InputStream inputStream = object.getObjectContent();
            FileOutputStream outputStream = new FileOutputStream(targetFile);) {
            byte[] buff = new byte[1024];
            while (inputStream.read(buff) != -1) {
                outputStream.write(buff);
            }
        }catch (Exception e){
            log.error("文件读取异常，bucketName:" + bucketName +", fileId: " + resourcePath, e);
            throw new StoreException(String.format("文件读取在异常, bucketName:%s, fileId:%s", bucketName, resourcePath),e);
        }
    }

    @Override
    public InputStream readAsInputStream(String resourcePath)throws StoreException  {
        return readAsInputStream(bucketName, resourcePath);
    }

    @Override
    public InputStream readAsInputStream(String bucketName, String resourcePath) throws StoreException  {
        if(bucketName == null){
            bucketName = this.bucketName;
        }
        try {
            S3Object object = amazonS3.getObject(bucketName, resourcePath);
            InputStream inputStream = object.getObjectContent();
            return inputStream;
        }catch (Exception e){
            log.error("文件读取异常readAsInputStream，bucketName:" + bucketName +", fileId: " + resourcePath, e);
            throw new StoreException(String.format("文件读取在异常, bucketName:%s, fileId:%s", bucketName, resourcePath),e);
        }
    }

    @Override
    public void deleteFile(String resourcePath) throws StoreException {
        deleteFile(this.bucketName, resourcePath);
    }


    @Override
    public void deleteFile(String bucketName, String resourcePath) throws StoreException {
        if(bucketName == null){
            bucketName = this.bucketName;
        }
        try {
            amazonS3.deleteObject(bucketName, resourcePath);
        }catch (Exception e){
            log.error("文件删除异常，bucketName:" + bucketName +", fileId: " + resourcePath, e);
            throw new StoreException(String.format("文件删除异常, bucketName:%s, fileId:%s", bucketName, resourcePath),e);
        }
    }
}
